/**
 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Autogenerated file -- DO NOT EDIT!

#if defined(PANDA_TARGET_AMD64) && !defined(PANDA_COMPILER_TARGET_X86_64)
    #define RUNTIME_HAS_NO_FASTPATH
    static constexpr bool FASTPATH_ENABLED = false;
#else
    static constexpr bool FASTPATH_ENABLED = true;
#endif

% Compiler::intrinsics.select(&:has_impl?).uniq{ |i| i.impl }.each do |intrinsic|
%     next if intrinsic.is_stub
%     if intrinsic.private
#ifndef PANDA_PRODUCT_BUILD
%     end
% impl = intrinsic.respond_to?(:fast_path) ? intrinsic.fast_path : intrinsic.impl
% if intrinsic.respond_to?(:fast_path)
    extern "C" void <%= intrinsic.impl.rpartition('::').last %>Bridge();
    extern "C" void <%= intrinsic.impl.rpartition('::').last %>RuntimeCallChecker();
% end
% if intrinsic.respond_to?(:fast_path)
#ifndef RUNTIME_HAS_NO_FASTPATH
    extern "C" void <%= impl.rpartition('::').last %>();
% else
    extern "C" void <%= impl.rpartition('::').last %>Bridge();
% end
    extern "C" void <%= impl.rpartition('::').last %>RuntimeCallChecker();
% if intrinsic.respond_to?(:fast_path)
#endif
% end
%     if intrinsic.private
#endif  // PANDA_PRODUCT_BUILD
%     end
% end

extern "C" void ObjectCloneStub();

// NOLINTNEXTLINE(readability-function-size)
inline RuntimeInterface::IntrinsicId GetIntrinsicEntryPointId(intrinsics::Intrinsic intrinsic) {
    switch (intrinsic)
    {
% Compiler::intrinsics.each do |intrinsic|
    case intrinsics::Intrinsic::<%= intrinsic.enum_name %>:
        return RuntimeInterface::IntrinsicId::<%= intrinsic.entrypoint_name %>;
% end
    default:
        return RuntimeInterface::IntrinsicId::COUNT;
    }
}

// NOLINTNEXTLINE(readability-function-size)
uintptr_t PandaRuntimeInterface::GetIntrinsicAddress(bool runtimeCall, [[maybe_unused]] SourceLanguage lang,
                                                     [[maybe_unused]] PandaRuntimeInterface::IntrinsicId id) const {
    switch (id) {
    case IntrinsicId::LIB_CALL_FMOD: {
        using Fp = double (*)(double, double);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(fmod));
    }
    case IntrinsicId::LIB_CALL_FMODF: {
        using Fp = float (*)(float, float);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(fmodf));
    }
    case IntrinsicId::LIB_CALL_LDEXP: {
        using Fp = double (*)(double, int);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(ldexp));
    }
    case IntrinsicId::LIB_CALL_LDEXPF: {
        using Fp = float (*)(float, int);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(ldexpf));
    }
    case IntrinsicId::LIB_CALL_EXP2: {
        using Fp = double (*)(double);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(exp2));
    }
    case IntrinsicId::LIB_CALL_EXP2F: {
        using Fp = float (*)(float);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(exp2f));
    }
    case IntrinsicId::LIB_CALL_MEM_COPY: {
        using Fp = void *(*)(void *, const void *, size_t);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(memcpy));
    }
    case IntrinsicId::LIB_CALL_MEMSET_8: {
        using Fp = void (*)(ObjectHeader *, uint8_t, uint32_t, uint32_t);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(ark::intrinsics::Memset8));
    }
    case IntrinsicId::LIB_CALL_MEMSET_16: {
        using Fp = void (*)(ObjectHeader *, uint16_t, uint32_t, uint32_t);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(ark::intrinsics::Memset16));
    }
    case IntrinsicId::LIB_CALL_MEMSET_32: {
        using Fp = void (*)(ObjectHeader *, uint32_t, uint32_t, uint32_t);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(ark::intrinsics::Memset32));
    }
    case IntrinsicId::LIB_CALL_MEMSET_64: {
        using Fp = void (*)(ObjectHeader *, uint64_t, uint32_t, uint32_t);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(ark::intrinsics::Memset64));
    }
    case IntrinsicId::LIB_CALL_MEMSET_F32: {
        using Fp = void (*)(ObjectHeader *, float, uint32_t, uint32_t);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(ark::intrinsics::Memsetf32));
    }
    case IntrinsicId::LIB_CALL_MEMSET_F64: {
        using Fp = void (*)(ObjectHeader *, double, uint32_t, uint32_t);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(ark::intrinsics::Memsetf64));
    }
    case IntrinsicId::LIB_CALL_MEM_MOVE: {
        using Fp = void *(*)(void *, const void *, size_t);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(memmove));
    }
    case IntrinsicId::LIB_CALL_MEM_SET: {
        using Fp = void *(*)(void *, int, size_t);
        return reinterpret_cast<uintptr_t>(static_cast<Fp>(memset));
    }

% Compiler::intrinsics.each do |intrinsic|
    case IntrinsicId::<%= intrinsic.entrypoint_name %>:
%   if !intrinsic.has_impl?
        return 0;
%     next
%   end
%   impl = intrinsic.respond_to?(:fast_path) ? intrinsic.fast_path : intrinsic.impl
%   bridge = intrinsic.respond_to?(:fast_path) ? intrinsic.fast_path : "#{intrinsic.impl.rpartition('::').last}Bridge"
%   if intrinsic.private
#ifndef PANDA_PRODUCT_BUILD
%   end
%   if intrinsic.is_stub
%     if intrinsic.codegen_arch.empty?
        return reinterpret_cast<uintptr_t>(<%= intrinsic.impl %>);
%     elsif intrinsic.codegen_arch.length == 1 && intrinsic.codegen_arch.include?('arm64')
#ifdef PANDA_TARGET_ARM64
        return reinterpret_cast<uintptr_t>(<%= intrinsic.impl %>);
#else
        return reinterpret_cast<uintptr_t>(nullptr);
#endif
%     else
        UNREACHABLE();
%     end
%   else
%     if intrinsic.respond_to?(:fast_path)
        if (!FASTPATH_ENABLED || !IsGcValidForFastPath(lang)) {
            return runtimeCall ? reinterpret_cast<uintptr_t>(<%= "#{intrinsic.impl.rpartition('::').last}Bridge" %>) :
#ifdef NDEBUG
                reinterpret_cast<uintptr_t>(<%= intrinsic.impl %>);
#else
                reinterpret_cast<uintptr_t>(<%= intrinsic.impl.rpartition('::').last %>RuntimeCallChecker);
#endif
        }
#ifndef RUNTIME_HAS_NO_FASTPATH
%     end
        return runtimeCall ? reinterpret_cast<uintptr_t>(<%= bridge %>) :
#ifdef NDEBUG
          reinterpret_cast<uintptr_t>(<%= impl %>);
#else
          reinterpret_cast<uintptr_t>(<%= impl.rpartition('::').last %>RuntimeCallChecker);
#endif
%     if intrinsic.respond_to?(:fast_path)
#endif
%     end
%   end
%   if intrinsic.private
#else
        return reinterpret_cast<uintptr_t>(intrinsics::UnknownIntrinsic);
#endif  // PANDA_PRODUCT_BUILD
%   end
% end
    default:
        UNREACHABLE();
    }
}
